<?php

namespace app\shell;

use app\service\AliyunProductService;
use app\service\AliyunProjectService;
use app\service\AliyunService;
use app\service\DeviceBaseService;
use Exception;
use share\console\CConsole;
use share\console\CLIRunner;
use share\model\LicenseV2Model;
use share\service\AmqpService;
use share\service\IdMakerService;
use share\service\MQService;
use share\utils\Helper;
use think\Log;

class CDeviceBase  extends CLIRunner
{
    // 同步信息
    // public function async_action(){
    //     $devices = DeviceBaseService::getNativeAll([
    //         'server_site' => ''
    //     ],null,'id ASC',0,100);
    // }

    public function async_server_site_action($id = 0)
    {
        // $pkInfo = AliyunProductService::getAllByFilter([]);
        $projectInfo = AliyunProjectService::getAllByFilter([
            'has_aliyun_cloud_access' => 1,
        ]);
        $id = intval($id);

        $times = 0;
        $size = 100;
        $startTime = time();
        $projectIds = array_column($projectInfo, 'id');
        if ($id < 1) {
            $lastData = DeviceBaseService::getNativeOne([
                'server_site' => ['<>', ''],
                'aliyun_project_id' => ['in', $projectIds],
            ], [
                'max(id)' => 'id'
            ]);
            if ($lastData) {
                $id = $lastData['id'];
            }
        }
        do {
            $tn = time();
            if ($tn - $startTime > 1800) {
                CConsole::print_line("already run 1800 seconds. exits!");
            }
            CConsole::print_line("do times " . $times);
            $devices = DeviceBaseService::getNativeAll([
                'server_site' => '',
                'aliyun_project_id' => ['in', $projectIds],
                'id' => ['>', $id],
            ], null, 'id ASC', 0, $size);
            $update = [];
            foreach ($devices as $device) {
                $pk = $device['pk'];
                $project =  Helper::filterOne($projectInfo, ['id' => $device['aliyun_project_id']]);
                $id = $device['id'];
                if (empty($project)) {
                    CConsole::print_line("pk {$pk} relation project id " . $device['aliyun_project_id'] . " not found!");
                    continue;
                }
                try {
                    $aliyun = AliyunService::instance($project['project_key'], 'CN');
                    $regionInfo = $aliyun->getRawThingRegoin($pk, $device['dn']);
                    if ($regionInfo) {
                        $region = AliyunService::getRegionByLocation($regionInfo);
                        if (!isset($update[$region])) {
                            $update[$region] = [];
                        }
                        $update[$region][] = $device['id'];
                    }
                } catch (Exception $e) {
                    trace($e->getMessage(), Log::ERROR);
                    CConsole::print_line("async server_site pk {$pk} dn:" . $device['dn'] . " err info is " . $e->getMessage());
                    CConsole::print_line("will continue at 2 seconds");
                    //sleep(2);
                    continue;
                }
            }

            foreach ($update as $region => $ids) {
                DeviceBaseService::updateByFilter([
                    'id' => ['in', $ids],
                ], [
                    'server_site' => $region,
                ]);
            }

            if (count($devices) < $size) {
                break;
            }

            if (count($update) < 1) {
                break;
            }
            $times++;
        } while (true);
    }

    /**
     * 同步 iot_id
     */
    public function async_iot_id_action($id = 0)
    {
        $projectInfo = AliyunProjectService::getAllByFilter([
            'has_aliyun_cloud_access' => 1,
        ]);
        $startTime = time();
        $times = 0;
        $size = 100;
        $id = intval($id);
        $projectIds = array_column($projectInfo, 'id');
        if ($id < 1) {
            $lastData = DeviceBaseService::getNativeOne([
                'iot_id' => ['NOT NULL', ''],
                'server_site' => ['<>', ''],
                'aliyun_project_id' => ['in', $projectIds],
            ], [
                'max(id)' => 'id'
            ]);
            if ($lastData) {
                $id = $lastData['id'];
            }
        }
        do {
            CConsole::print_line("do times " . $times);
            $tn = time();
            if ($tn - $startTime > 1800) {
                CConsole::print_line("already run 1800 seconds. exits!");
            }
            $devices = DeviceBaseService::getNativeAll([
                'iot_id' => null,
                'server_site' => ['<>', ''],
                'aliyun_project_id' => ['in', $projectIds],        
            ], null, 'id ASC', 0, $size);
            foreach ($devices as $device) {
                $pk = $device['pk'];
                $id = $device['id'];
                $project =  Helper::filterOne($projectInfo, ['id' => $device['aliyun_project_id']]);
                if (empty($project)) {
                    CConsole::print_line("pk {$pk} relation project id " . $device['aliyun_project_id'] . " not found!");
                    continue;
                }
                try {
                    $aliyun = AliyunService::instance($project['project_key'], $device['server_site']);
                    $thingInfo = $aliyun->getRawThingInfo(null, $pk, $device['dn']);
                    if ($thingInfo) {
                        DeviceBaseService::update($device['id'], [
                            'iot_id' => $thingInfo['iotId'],
                        ]);
                    }
                } catch (Exception $e) {
                    trace($e->getMessage(), Log::ERROR);
                    CConsole::print_line("async iot_id pk {$pk} dn:" . $device['dn'] . " err info is " . $e->getMessage());
                    CConsole::print_line("will continue at 2 seconds");
                    //sleep(2);
                    continue;
                }
            }
            if (count($devices) < $size) {
                break;
            }
            $times++;
        } while (true);
    }

    public function async_by_amqp_action($size = 50000){
        $devices = DeviceBaseService::getNativeAll("`iot_id` IS NULL OR server_site = ''", ['id'], 'updated ASC', 0, $size);
      
        foreach($devices as $index => $device){
            $data = [
                'service' => 'app\\service\\DeviceBaseService@async',
                'params' => [
                    $device['id']
                ]
            ];
            AmqpService::instance()->simplePush($data);
            if($index > 0 && ($index % 1000 == 0) ) { // 限速
                sleep(3);
            }
        }
    }

    public function async_by_cli_action($size = 50000){
        $devices = DeviceBaseService::getNativeAll("aliyun_project_id = 15 AND (`iot_id` IS NULL OR server_site = '')", ['id'], 'updated ASC', 0, $size);
      
        foreach($devices as $index => $device){
            // $data = [
            //     'service' => 'app\\service\\DeviceBaseService@async',
            //     'params' => [
            //         $device['id']
            //     ]
            // ];
            // AmqpService::instance()->simplePush($data);
            DeviceBaseService::async($device['id']);
            if($index > 0 && ($index % 100 == 0) ) { // 限速
                sleep(3);
            }
        }
    }


    public function export_burn_super_device_as_sql_action(){
        $vendors = [
            'aenzi',
            'aevision',
            'asbdefe',
            'enz',
            'fslink',
            'hbgk',
            'hdt',
            'horizonai',
            'peaf',
            'powerview',
            'secview',
            'smalon',
            'tungson',
            'xiaoding',
            'zdtec',
            'zkteco',
        ];
        $types = ['nvr','ipcam'];      
        $size = 1000;
        $products = AliyunProductService::getAllByFilter([]);
        $tn = time();
        foreach($vendors as $vendor){
            foreach($types as $type){  
                CConsole::print_line("-- backup for {$vendor}_{$type}_license_v2");    
                $page = 1;
                do{
                    $model = new LicenseV2Model();
                    $model = $model->setBase($vendor,$type);
                    $data =  $model->getQuery(true)->field('device_name,product_key,serial_no')->order('update_time ASC')->page($page,$size)->select();               
                    $res = $model->formatCollectionData($data);
                    $count = count($res);
                    if($count > 0){
                        CConsole::print_line("UPDATE id_maker SET `num` = `num` + $count WHERE `name` = 'device_base';"); 
                        foreach($res as $item){
                            $dn = $item['device_name'];
                            $pk = $item['product_key'];
                            $sn = $item['serial_no'];
                            $product = Helper::filterOne($products,['pk' => $pk]);
                            if($product){
                                $projectId = $product['aliyun_project_id'];
                                CConsole::print_line("INSERT INTO `device_base`(`pk`,`dn`,`serial_no`,`aliyun_project_id`,`created`,`updated`) VALUES('$pk','$dn','$sn',0,$projectId,$tn,$tn) ON DUPLICATE KEY UPDATE `serial_no` = '$sn',`updated` = IF(`serial_no` = '$sn',0,$tn);");
                            }
                            else{
                                CConsole::print_line("-- pk : {$pk} not found ");
                            }
                        } 
                    }
                    $page++;
                }while($count >= $size);
            }
        }
        exit(0);
    }

    /**
     * 冲烧录中心同步数据
     */
    public function async_from_burn_super_action($date = 0){
        if(empty($date)){
            $time = date("Y-m-d",strtotime("-1 day"));
        }
        else{
            $time = date("Y-m-d",strtotime($date));
        }
        $time = strtotime($time);
        $vendors = [
            'aenzi',
            'aevision',
            'asbdefe',
            'enz',
            'fslink',
            'hbgk',
            'hdt',
            'horizonai',
            'peaf',
            'powerview',
            'secview',
            'smalon',
            'tungson',
            'xiaoding',
            'zdtec',
            'zkteco',
        ];
        $types = ['nvr','ipcam'];      
        $size = 300;
        foreach($vendors as $vendor){
            foreach($types as $type){      
                $page = 1;   
                do{
                    $model = new LicenseV2Model();
                    $model = $model->setBase($vendor,$type);
                    $data =  $model->getQuery(true)->field('device_name,product_key,serial_no')->order('update_time ASC')->page($page,$size)->where('update_time','>',$time)->select();               
                    $res = $model->formatCollectionData($data);
                    if(count($res) > 0 ){
                        $dns = array_column($res,'device_name');
                        $origins = DeviceBaseService::getNativeAll([
                            'dn' => ['in',$dns]
                        ]);
                        $adds = [];
                        $update = [];
                        foreach($res as $item){
                            $dn = $item['device_name'];
                            $pk = $item['product_key'];
                            $sn = $item['serial_no'];
                            $exist = Helper::filterOne($origins,['dn' => $dn,'pk' => $pk]);
                            if(empty($exist)){
                                $adds[] = [
                                    'pk' => $pk,
                                    'dn' => $dn,
                                    'sn' => $sn,
                                ];
                            }
                            else{
                                if($exist['serial_no'] != $sn){
                                    $update[] = [
                                        'id' => $exist['id'],
                                        'sn' => $sn,
                                    ];
                                }
                            }
                        }    
                        if(count($adds) > 0){
                            self::AddMutilDevice($adds);
                        }
                        else{
                            foreach($update as $item){
                                DeviceBaseService::update($item['id'],[
                                    'serial_no' => $item['sn']
                                ]);
                            }
                        }
                    }
                    $page++;  
                    sleep(2); // 避免CPU过高 堵死服务器
                }while(count($res) >= $size);
            }
        }
        return $time;
    }


    public static function AddMutilDevice($items){
        $products = AliyunProductService::getAllByFilter([]);
        $tn = time();        
        $ids = IdMakerService::makeMutil(IdMakerService::NAME_OF_DEVICE_BASE,count($items));
        
        foreach($items as $index => $item){
            $id = $ids[$index];
            $product = Helper::filterOne($products,['pk' => $item['pk']]);         
            DeviceBaseService::upsert([
                'id' => $id,
                'pk' => $item['pk'],
                'dn' => $item['dn'],
                'serial_no' => $item['sn'],
                'aliyun_project_id' => $product ? $product['aliyun_project_id'] : 0,
                'created' => $tn,
                'updated' => $tn,
            ], [
                'serial_no' => $item['sn'],
                'updated' => $tn,
            ]);

            AmqpService::simplePush([
                'service' => 'app\\service\\DeviceBaseService@async',
                'params' => [
                     $id
                ],
            ]);

            // // 同步一下
            // MQService::push([
            //     'service' => 'app\\service\\DeviceBaseService@async',
            //     'params' => [
            //          $id
            //     ],
            //  ], MQService::CHANNEL_OF_ACCOUNT);
        }

    }
}
